\subsection{CRT (win32)}
\label{sec:CRT}
\myindex{CRT}

Начинается ли исполнение программы прямо с функции \main{}?
Нет, не начинается.
Если открыть любой исполняемый файл в \IDA или Hiew, 
то \ac{OEP} указывает на какой-то совсем другой код.

Это код, который делает некоторые приготовления перед тем как запустить ваш код.
Он называется стартап-код или CRT-код (C RunTime). \\
\\
Функция \main{} принимает на вход массив из параметров, переданных в командной строке, а также
переменные окружения.
Но в реальности в программу передается командная строка в виде простой строки, это именно
CRT-код находит там пробелы и разрезает строку на части.
CRT-код также готовит массив переменных окружения \TT{envp}.
В \ac{GUI}-приложениях win32, вместо \main{} имеется функция \TT{WinMain} со своими аргументами:

\begin{lstlisting}[style=customc]
int CALLBACK WinMain(
  _In_  HINSTANCE hInstance,
  _In_  HINSTANCE hPrevInstance,
  _In_  LPSTR lpCmdLine,
  _In_  int nCmdShow
);
\end{lstlisting}

CRT-код готовит и их.

А также, число, возвращаемое функцией \main{}, это код ошибки возвращаемый программой.
В CRT это значение передается в \TT{ExitProcess()}, принимающей в качестве аргумента код ошибки. \\
\\
Как правило, каждый компилятор имеет свой CRT-код. \\
\\
Вот типичный для MSVC 2008 CRT-код.

\lstinputlisting[numbers=left,style=customasmx86]{OS/win32_CRT/crt_msvc_2008.asm}

Здесь можно увидеть по крайней мере вызов
функции \TT{GetCommandLineA()} (строка 62), 
затем \TT{setargv()} (строка 66) и \TT{setenvp()} (строка 74),
которые, видимо, заполняют глобальные переменные-указатели
\TT{argc}, \TT{argv}, \TT{envp}.

В итоге, вызывается \main{} с этими аргументами (строка 97).

Также имеются вызовы функций с говорящими именами вроде \TT{heap\_init()} (строка 35), \TT{ioinit()} (строка 54).

\glslink{heap}{Куча} действительно инициализируется в \ac{CRT}.
Если вы попытаетесь использовать \TT{malloc()} в программе без CRT, программа упадет с такой ошибкой:

\begin{lstlisting}
runtime error R6030
- CRT not initialized
\end{lstlisting}

Инициализация глобальных объектов в \Cpp происходит до вызова \main{}, именно в \ac{CRT}: 
\myref{sec:std_string_as_global_variable}.

Значение, возвращаемое из \main{} передается или в \TT{cexit()}, 
или же в \TT{\$LN32}, которая далее вызывает \TT{doexit()}.

Можно ли обойтись без \ac{CRT}? Можно, если вы знаете что делаете.

В линкере от \ac{MSVC} точка входа задается опцией \TT{/ENTRY}.

\begin{lstlisting}[style=customc]
#include <windows.h>

int main()
{
	MessageBox (NULL, "hello, world", "caption", MB_OK);
};
\end{lstlisting}

Компилируем в MSVC 2008.

\begin{lstlisting}
cl no_crt.c user32.lib /link /entry:main
\end{lstlisting}

Получаем вполне работающий .exe размером 2560 байт, внутри которого есть только PE-заголовок, инструкции, 
вызывающие \TT{MessageBox},
две строки в сегменте данных, импортируемая из \TT{user32.dll} функция \TT{MessageBox}, и более ничего.

Это работает, но вы уже не сможете вместо \main{} написать \TT{WinMain} с его четырьмя аргументами.
Вернее, если быть точным, написать-то сможете, но доступа к этим аргументам не будет, 
потому что они не подготовлены на момент исполнения.

Кстати, можно еще короче сделать .exe если уменьшить 
выравнивание \ac{PE}-секций (которое, по умолчанию, 4096 байт).

\begin{lstlisting}
cl no_crt.c user32.lib /link /entry:main /align:16
\end{lstlisting}

Линкер скажет:

\begin{lstlisting}
LINK : warning LNK4108: /ALIGN specified without /DRIVER; image may not run
\end{lstlisting}

Получим .exe размером 720 байт.
Он запускается в Windows 7 x86, но не x64 
(там выдает ошибку при загрузке).
При желании, размер можно еще сильнее ужать, но, как видно, 
возникают проблемы с совместимостью с разными версиями Windows.

